home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-2.iso / extra_2 / flmgmtcl.zip / PATH.CPP < prev    next >
C/C++ Source or Header  |  1995-11-02  |  30KB  |  1,057 lines

  1. // ==========================================================================
  2. //                             Class Implementation : CPathSpec
  3. // ==========================================================================
  4.  
  5. // Source file : path.cpp
  6.  
  7. // Source : Periphere NV (R.Mortelmans)
  8. // Creation Date :        2nd November 1995
  9. // Last Modification : 2nd November 1995
  10.                           
  11. // //////////////////////////////////////////////////////////////////////////
  12.  
  13. #include "stdafx.h"        // standard MFC include
  14. #include "path.h"        // class specification
  15. #include "xstring.h"    // for string-int conversion
  16. #ifndef WIN32
  17. #include "toolhelp.h"    // To determine the module handle
  18. #endif
  19.  
  20. #include <direct.h>        // For directory functions (_fullpath, ...)
  21. #include <dos.h>        // For _dos_setfileattr, ...
  22. #include <io.h>            // For _chsize()
  23.  
  24. #ifdef _DEBUG
  25. #undef THIS_FILE
  26. static char BASED_CODE THIS_FILE[] = __FILE__;
  27. #endif
  28.  
  29. IMPLEMENT_DYNAMIC(CPathSpec, CDirSpec)
  30.  
  31. #define new DEBUG_NEW
  32.  
  33. /////////////////////////////////////////////////////////////////////////////
  34. // Definition of static members
  35.  
  36.  
  37. // Data members -------------------------------------------------------------
  38. // protected:
  39.  
  40. // private:
  41.  
  42. // Member functions ---------------------------------------------------------
  43. // public:
  44.  
  45. CPathSpec::CPathSpec()
  46.     {
  47.     }
  48.     
  49. CPathSpec::CPathSpec(const char* pszPath)
  50.     {
  51.     if (!SetPath(pszPath))
  52.         {
  53.         TRACE(TEXT("CPathSpec::CPathSpec : An invalid path (%s) was specified, clearing object\n"),
  54.             pszPath);
  55.         SetPath(TEXT(""));
  56.         }
  57.     }
  58.     
  59. CPathSpec::CPathSpec(const CPathSpec& pathSrc)
  60.     :
  61.     CDirSpec(pathSrc),
  62.     CFileSpec(pathSrc)
  63.     {
  64.     }
  65.     
  66. const CPathSpec& CPathSpec::operator=(const CPathSpec& pathSrc)
  67.     {
  68.     CDirSpec::operator=(pathSrc);
  69.     CFileSpec::operator=(pathSrc);
  70.     return *this;
  71.     }
  72.     
  73. CString CPathSpec::GetPath() const
  74.     {
  75.     CString sDir = GetDirectory();
  76.     CString sFile = GetFileName();
  77.     CString sPath;
  78.     if (!sFile.IsEmpty())
  79.         if (!sDir.IsEmpty())
  80.             if (sDir.Right(1) != CString(TEXT("\\")))
  81.                 // \\DIR and AAA.BBB
  82.                 sPath = sDir + TEXT("\\") + sFile;
  83.             else
  84.                 // \\ and AAA.BBB
  85.                 sPath = sDir + sFile;
  86.         else
  87.             // empty and AAA.BBB
  88.             sPath = sFile;
  89.     else
  90.         // \\DIR and empty
  91.         sPath = sDir;
  92.     return sPath;;
  93.     }
  94.     
  95. BOOL CPathSpec::SetPath(const char* pszPath)
  96.     {            
  97.     char pszDrive[_MAX_DRIVE];
  98.     char pszSubdir[_MAX_DIR];
  99.     char pszBaseName[_MAX_FNAME];
  100.     char pszExtender[_MAX_EXT];
  101.     
  102.     _splitpath(pszPath, pszDrive, pszSubdir, pszBaseName, pszExtender);
  103.     int nSubDir = strlen(pszSubdir);
  104.     if (1 < nSubDir)
  105.         // ... When not empty and not root, remove trailing back slash
  106.         pszSubdir[nSubDir - 1] = '\0';
  107.     int nExt = strlen(pszExtender);
  108.     if (1 <= nExt)
  109.         // ... Remove leading full stop
  110.         strcpy(pszExtender, pszExtender + 1);
  111.     
  112.     return SetDrive(pszDrive) && SetSubdirectory(pszSubdir) &&
  113.            SetBaseName(pszBaseName) && SetExtender(pszExtender);
  114.     }
  115.     
  116. void CPathSpec::ForceSetPath(const char* pszPath)
  117.     {            
  118.     char pszDrive[_MAX_DRIVE];
  119.     char pszSubdir[_MAX_DIR];
  120.     char pszBaseName[_MAX_FNAME];
  121.     char pszExtender[_MAX_EXT];
  122.     
  123.     _splitpath(pszPath, pszDrive, pszSubdir, pszBaseName, pszExtender);
  124.     int nSubDir = strlen(pszSubdir);
  125.     if (1 < nSubDir)
  126.         // ... When not empty and not root, remove trailing back slash
  127.         pszSubdir[nSubDir - 1] = '\0';
  128.     int nExt = strlen(pszExtender);
  129.     if (1 <= nExt)
  130.         // ... Remove leading full stop
  131.         strcpy(pszExtender, pszExtender + 1);
  132.     
  133.     ForceSetDrive(pszDrive);
  134.     ForceSetSubdirectory(pszSubdir);
  135.     ForceSetBaseName(pszBaseName);
  136.     ForceSetExtender(pszExtender);
  137.     }
  138.     
  139. BOOL CPathSpec::SetPath(const CDirSpec dirSpec, const CFileSpec fileSpec)
  140.     {
  141.     CDirSpec::operator=(dirSpec);
  142.     CFileSpec::operator=(fileSpec);
  143.     return TRUE;
  144.     }
  145.     
  146. CString CPathSpec::GetShortDescription()
  147.     {
  148.     // ... If path spec is empty, just return
  149.     if (GetPath().IsEmpty())
  150.         return TEXT("");
  151.  
  152.     CPathSpec tempPath(*this);
  153.     CString sLastSubdir;
  154.     CString sEliminatedDirs = TEXT("\\..\\");
  155.  
  156.     // First try to make absolute path
  157.     if (!tempPath.MakeAbsolute())
  158.         {
  159.         TRACE(TEXT("CPathSpec::GetShortDescription : Could not make absolute path, returning full path spec\n"));
  160.         return GetPath();
  161.         }
  162.  
  163.     // Get the last subdir
  164.     sLastSubdir = tempPath.GetLastSubdirectory().GetSubdirectory();
  165.     // ... Last subdir should never contain back slashes
  166.     ASSERT(sLastSubdir.Find('\\') == -1);
  167.     // ... If last subdir is empty (root) or equals dir itself, 
  168.     //     no subdirs have been eliminated
  169.     if (sLastSubdir.IsEmpty())
  170.         sEliminatedDirs.Empty();
  171.         else if ((TEXT("\\") + sLastSubdir) == tempPath.GetSubdirectory())
  172.             sEliminatedDirs = TEXT("\\");
  173.  
  174.     // Return the composed short description
  175.     return tempPath.GetDrive() + sEliminatedDirs + sLastSubdir + TEXT("\\") + tempPath.GetFileName();
  176.     }
  177.  
  178. BOOL CPathSpec::MakeTemp(BOOL bCreateEmpty /* = TRUE */,  const char* pszPrefix /* = TEXT("TMP") */)
  179.     {
  180.     char path_buffer[_MAX_PATH + 1];
  181.     *path_buffer = '\0'; 
  182.  
  183. #ifdef WIN32
  184.     // Get temp path
  185.     CString sTempPath;
  186.     BOOL bSucces = ::GetTempPath(_MAX_PATH, sTempPath.GetBuffer(_MAX_PATH));
  187.     sTempPath.ReleaseBuffer();
  188.  
  189.     if (!bSucces)
  190.         return FALSE;
  191.  
  192.     if (!::GetTempFileName(sTempPath,    // Use the default drive
  193.                            pszPrefix,    // Temporary file name prefix
  194.                            0,             // Generate number and create file
  195.                            path_buffer)) // Result
  196.         return FALSE;
  197.  
  198. #else
  199.     // Get temp path
  200.     ::GetTempFileName(0,            // Use the default drive
  201.                       pszPrefix,    // Temporary file name prefix
  202.                       0,             // Generate number and create file
  203.                       path_buffer); // Result
  204. #endif
  205.  
  206.     if (*path_buffer != '\0')
  207.         {
  208.         BOOL bResult = SetPath(path_buffer);
  209.         if (bCreateEmpty)
  210.             {
  211.             // Empty file should have been created by ::GetTempFileName
  212.             ASSERT(Exists());
  213.             }
  214.         else
  215.             {
  216.             // Delete empty file created by ::GetTempFileName
  217.             VERIFY(DoRemove());
  218.             ASSERT(!Exists());
  219.             }
  220.         return bResult;
  221.         }
  222.     else
  223.         {
  224.         TRACE(TEXT("CPathSpec::MakeTemp : Could not make temporary path spec\n"));
  225.         return FALSE;
  226.         }
  227.     }
  228.  
  229. BOOL CPathSpec::MakeAbsolute()
  230.     {
  231.     // If no file name was specified, just return
  232.     // Apparently in WIN32 _fullpath returns the apllications full path
  233.     //  in this case (??)
  234.     if (GetFileName().IsEmpty())
  235.         return TRUE;
  236.  
  237.     char pszFullPath[_MAX_PATH];
  238.     if (_fullpath(pszFullPath, (const char*)GetPath(), _MAX_PATH) != NULL)
  239.         return SetPath(pszFullPath);
  240.     else
  241.         return FALSE;
  242.     }
  243.     
  244. BOOL CPathSpec::MakeUnique()
  245.     {
  246.     if (GetBaseName().IsEmpty())
  247.         SetBaseName(TEXT("unique"));
  248.         
  249.     if (!Exists())
  250.         return TRUE;  
  251.  
  252.     // Change the name by first adding underscores, until 8 characters are used.
  253.     // Then the last character(s) are replaced by a number starting from 2,
  254.     // until a unique name is found.
  255.     CXString sNumber = TEXT("2");
  256.     CString sBaseName = GetBaseName().Left(8);
  257.     while (sBaseName.GetLength() < 8)
  258.         sBaseName +=  TEXT("_");          
  259.         
  260.     ASSERT(sBaseName.GetLength() == 8);
  261.     ASSERT(Exists());
  262.     do
  263.         {
  264.         sBaseName = sBaseName.Left(8 - sNumber.GetLength());
  265.         sBaseName += sNumber;
  266.         VERIFY(SetBaseName(sBaseName));
  267.         sNumber = sNumber.GetInt() + 1;        // Implicit conversion to int
  268.         }
  269.         while(Exists());
  270.         
  271.     return TRUE;
  272.     }
  273.     
  274. BOOL CPathSpec::Exists() const
  275.     {
  276.     CFileStatus fileStatus;
  277.     return CFile::GetStatus(GetPath(), fileStatus);
  278.     }
  279.     
  280. BOOL CPathSpec::IsEmpty() const
  281.     {
  282.     return CDirSpec::IsEmpty() && CFileSpec::IsEmpty();
  283.     }
  284.     
  285. void CPathSpec::Empty()
  286.     {
  287.     CDirSpec::Empty();
  288.     CFileSpec::Empty();
  289.     }
  290.     
  291. BOOL CPathSpec::DoSearch(CFileSpec fileName, CDirSpec startingDir /* = CDirSpec() */,
  292.          BOOL bRecursively /* = FALSE */)
  293.     {
  294.     CPathSpec resultPath;
  295.     CDirSpec currentDir;
  296.     
  297.     // First store the current dir
  298.     VERIFY(currentDir.DoGetCurrentDir());
  299.     
  300.     // 1. Check the specified directory
  301.     if (!startingDir.IsEmpty())
  302.         {
  303.         resultPath.SetPath(startingDir, fileName);
  304.         if (resultPath.Exists())
  305.             {
  306.             *this = resultPath;
  307.             return TRUE;
  308.             }
  309.         }
  310.         
  311.     // 2. Check the subdirectories of the specified directory
  312.     
  313.     // ... Recursive search is not yet implemented
  314.     ASSERT(!bRecursively);
  315.  
  316.     // 3  Check the EXE-directory
  317.     char pszModulePath[_MAX_PATH];
  318.     if (::GetModuleFileName(GetThisModule(), pszModulePath, _MAX_PATH) != 0)
  319.         {
  320.         VERIFY(resultPath.SetPath(pszModulePath));
  321.         resultPath.CFileSpec::operator=(fileName);
  322.         if (resultPath.Exists())
  323.             {
  324.             *this = resultPath;
  325.             return TRUE;
  326.             }
  327.         }
  328.     else
  329.         {
  330.         TRACE(TEXT("CPathSpec::DoSearch : Could not retrieve the path of the running application\n"));
  331.         }
  332.     
  333.     // 4. Check the current directory
  334.     if (!currentDir.IsEmpty())
  335.         {
  336.         resultPath.SetPath(currentDir, fileName);
  337.         if (resultPath.Exists())
  338.             {
  339.             *this = resultPath;
  340.             return TRUE;
  341.             }
  342.         }
  343.  
  344.     // 5. Check the Windows directory
  345.     char pszWinDir[_MAX_DIR];
  346.     if (::GetWindowsDirectory(pszWinDir, _MAX_DIR) != 0)
  347.         {
  348.         VERIFY(resultPath.SetDirectory(pszWinDir));
  349.         resultPath.CFileSpec::operator=(fileName);
  350.         if (resultPath.Exists())
  351.             {
  352.             *this = resultPath;
  353.             return TRUE;
  354.             }
  355.         }
  356.     else
  357.         {
  358.         TRACE(TEXT("CPathSpec::DoSearch : Could not retrieve the Windows directory\n"));
  359.         }
  360.  
  361.     // 6. Check the System directory
  362.     char pszSystemDir[_MAX_DIR];
  363.     if (::GetSystemDirectory(pszSystemDir, _MAX_DIR) != 0)
  364.         {
  365.         VERIFY(resultPath.SetDirectory(pszSystemDir));
  366.         resultPath.CFileSpec::operator=(fileName);
  367.         if (resultPath.Exists())
  368.             {
  369.             *this = resultPath;
  370.             return TRUE;
  371.             }
  372.         }
  373.     else
  374.         {
  375.         TRACE(TEXT("CPathSpec::DoSearch : Could not retrieve the Windows directory\n"));
  376.         }
  377.  
  378.     // 7. Check the directories of PATH-environment variable
  379.     char pszResultPath[_MAX_PATH];
  380.     if (SearchEnvironment(fileName.GetFileName(), TEXT("PATH"), pszResultPath))
  381.         {
  382.         ASSERT(*pszResultPath != '\0');
  383.         VERIFY(SetPath(pszResultPath));
  384.         return TRUE;
  385.         }
  386.  
  387.     // If still not returned, the file was not found
  388.     return FALSE;
  389.     }
  390.     
  391. BOOL CPathSpec::DoCopy(CPathSpec destinationPath) const
  392.     {
  393.     ASSERT(!GetFileName().IsEmpty());        // Source file must be specified
  394.     CString sSourcePath;
  395.     CString sDestPath;
  396.     if (destinationPath.GetFileName().IsEmpty())
  397.         // ... Make destination file name equal to source
  398.         destinationPath.SetFileName(GetFileName());      
  399.     sSourcePath = GetPath();
  400.     sDestPath = destinationPath.GetPath();
  401.     
  402. #ifdef _DEBUG
  403.     if (!Exists())
  404.         {
  405.         TRACE(TEXT("CPathSpec::DoCopy : Source file %s does not exist\n"), sSourcePath);
  406.         return FALSE;
  407.         }
  408.     else
  409.         if (destinationPath.Exists())
  410.             TRACE(TEXT("CPathSpec::DoCopy : Destination file %s already exists, truncating ...\n"), sDestPath);
  411. #endif    
  412.  
  413.     const nBufferLength = 2048;
  414.     BYTE pBuffer[nBufferLength + 1];
  415.     int nLengthRead;
  416.     CFile source;
  417.     CFile dest;
  418.     BOOL bSuccess = TRUE;
  419.     TRY
  420.         {
  421.         if ( (source.Open(sSourcePath,CFile::modeRead | CFile::shareCompat) != 0) &&
  422.              (dest.Open(sDestPath, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive) != 0) )
  423.              {
  424.             do
  425.                 {
  426.                 nLengthRead = source.Read(pBuffer, nBufferLength);
  427.                 dest.Write(pBuffer, nLengthRead);
  428.                 }
  429.                 while (nLengthRead == nBufferLength);    // So while not EOF
  430.             source.Close();
  431.             dest.Close();
  432.             }
  433.         else
  434.             {
  435.             TRACE(TEXT("CPathSpec::DoCopy : Could not open files\n"));
  436.             bSuccess = FALSE;
  437.             }
  438.         }
  439.     CATCH(CFileException, pxFile)
  440.         {
  441.         TRACE(TEXT("CPathSpec::DoCopy : Catching FileException (%XH)\n"), pxFile->m_cause);
  442.         bSuccess = FALSE;
  443.         }
  444.     END_CATCH      
  445.     
  446.     return bSuccess;            
  447.     }
  448.     
  449. BOOL CPathSpec::DoMove(CPathSpec destinationPath) const
  450.     {
  451.     if (destinationPath.GetDrive() == TEXT(""))
  452.         VERIFY(destinationPath.SetDrive(GetDrive()));
  453.     if (destinationPath.GetSubdirectory() == TEXT(""))
  454.         VERIFY(destinationPath.SetSubdirectory(GetSubdirectory()));
  455.     if (destinationPath.GetFileName() == TEXT(""))
  456.         VERIFY(destinationPath.SetFileName(GetFileName()));
  457.     if (*this == destinationPath)
  458.         {
  459.         TRACE(TEXT("CPathSpec::DoMove : Source and destination files are the same %s\n"), 
  460.             (const char*)GetPath());
  461.         // ... Nothing to do
  462.         return TRUE;
  463.         }
  464.         
  465. #ifdef _DEBUG
  466.     if (!Exists())
  467.         TRACE(TEXT("CPathSpec::DoMove : Source file %s does not exist\n"), 
  468.             (const char*)GetPath());
  469.     if (destinationPath.Exists())
  470.         TRACE(TEXT("CPathSpec::DoMove : Destination file %s does not exist\n"), 
  471.             (const char*)destinationPath.GetPath());
  472. #endif
  473.     
  474.     // ... Assume success
  475.     BOOL bSuccess = TRUE;
  476.     TRY
  477.         {
  478.         CFile::Rename(GetPath(), destinationPath.GetPath());
  479.         }
  480.     CATCH(CFileException, px)
  481.         {
  482.         TRACE(TEXT("CPathSpec::DoMove : CFile::Rename(%s, %s) failed with CFileException cause %i\n"), 
  483.             (const char*)GetPath(), (const char*)destinationPath.GetPath(), px->m_cause);
  484.         bSuccess = FALSE;
  485.         }
  486.     END_CATCH
  487.     return bSuccess;
  488.     }
  489.     
  490. BOOL CPathSpec::DoRemove(BOOL bIgnoreReadOnly /* = FALSE */) const
  491.     {
  492.     CString sPath = GetPath();
  493.     
  494.     // ... This function may only be used to remove a file,
  495.     //       not a directory. So the file name must not be empty
  496.     ASSERT(!GetFileName().IsEmpty());
  497.  
  498. #ifdef _DEBUG
  499.     if (!Exists())
  500.         TRACE(TEXT("CPathSpec::DoRemove : File %s does not exist\n"), sPath);
  501. #endif    
  502.     if (bIgnoreReadOnly)
  503. #ifdef WIN32
  504.         if (!SetFileAttributes(sPath, CFile::normal))
  505. #else
  506.         if(_dos_setfileattr(sPath, CFile::normal))
  507. #endif
  508.             {
  509.             TRACE(TEXT("CPathSpec::DoRemove : File not found or cannot remove R/O attribute of %s\n"), sPath);
  510.             return FALSE;
  511.             }
  512.             
  513.     if (remove(sPath))
  514.         {
  515.         TRACE(TEXT("CPathSpec::DoRemove : Cannot remove file %s\n"), sPath);
  516.         return FALSE;
  517.         }            
  518.     return TRUE;
  519.     }
  520.     
  521. BOOL CPathSpec::DoGetInfo()
  522.     {
  523.     CFileStatus fileStatus;
  524.     if (CFile::GetStatus(GetPath(), fileStatus))
  525.         {
  526.         m_time =         fileStatus.m_mtime;
  527.         m_lnLength =     fileStatus.m_size;
  528.         m_eAttributes = fileStatus.m_attribute;
  529.         return TRUE;
  530.         }
  531.     else
  532.         {
  533.         TRACE(TEXT("CPathSpec::DoGetInfo : Could not get file status of %s\n"),
  534.             GetPath());
  535.         return FALSE;
  536.         }
  537.     }
  538.     
  539. BOOL CPathSpec::DoSetTime()
  540.     {
  541.     CFileStatus fileStatus;
  542.     
  543.     if (!CFile::GetStatus(GetPath(), fileStatus))
  544.         {
  545.         TRACE(TEXT("CPathSpec::DoSetTime : Could not even get the present status, failing\n"));
  546.         return FALSE;
  547.         }
  548.  
  549.     // Set new time, (DOS only knows one type of time)        
  550.     fileStatus.m_ctime = m_time;;
  551.     fileStatus.m_mtime = fileStatus.m_ctime;
  552.     fileStatus.m_atime = fileStatus.m_ctime;
  553.     
  554.     BOOL bSuccess = TRUE;
  555.     TRY
  556.         {
  557.         CFile::SetStatus(GetPath(), fileStatus);
  558.         }
  559.     CATCH(CFileException, pxFile)
  560.         {
  561.         TRACE(TEXT("CPathSpec::DoSetTime : Catching file exception (cause %XH)"),
  562.                 ((CFileException*)pxFile)->m_cause);
  563.         bSuccess = FALSE;
  564.         }
  565.     END_CATCH
  566.     return bSuccess;
  567.     }
  568.     
  569. BOOL CPathSpec::DoSetLength()
  570.     {
  571.     // SetStatus does not set the file length, so we use direct dos access
  572. #ifdef WIN32
  573.     HANDLE hFile;
  574.     hFile = CreateFile(GetPath(), GENERIC_READ | GENERIC_WRITE, 
  575.             0,NULL, OPEN_EXISTING, 
  576.             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
  577.     if (hFile == INVALID_HANDLE_VALUE)
  578.         {
  579.         TRACE(TEXT("CPathSpec::DoSetLength : Could not open file %s, failing\n"),
  580.             (const char*)GetPath());
  581.         return FALSE;
  582.         }
  583.     SetFilePointer(hFile,m_lnLength, NULL,FILE_BEGIN);
  584.     if(GetLastError() != ERROR_SUCCESS)
  585.         {
  586.         TRACE(TEXT("CPathSpec::DoSetLength : Could set new length of %s, failing\n"),
  587.             (const char*)GetPath());
  588.         return FALSE;
  589.         }
  590.     SetEndOfFile(hFile);
  591.     if(GetLastError() != ERROR_SUCCESS)
  592.         {
  593.         TRACE(TEXT("CPathSpec::DoSetLength : Could not set end of %s, failing\n"),
  594.             (const char*)GetPath());
  595.         return FALSE;
  596.         }
  597.     if (!CloseHandle(hFile))
  598.         {
  599.         TRACE(TEXT("CPathSpec::DoSetLength : Could not close file %s, failing\n"),
  600.             (const char*)GetPath());
  601.         return FALSE;
  602.         }
  603.     
  604. #else
  605.     UINT nErr;
  606.     int handle;
  607.     if ((nErr = _dos_open(GetPath(), CFile::modeReadWrite, &handle)) != 0)
  608.         {
  609.         TRACE(TEXT("CPathSpec::DoSetLength : Could not open file %s, failing\n"),
  610.             (const char*)GetPath());
  611.         return FALSE;
  612.         }
  613.     if ((nErr = _chsize(handle, m_lnLength)) != 0)
  614.         {
  615.         TRACE(TEXT("CPathSpec::DoSetLength : Could set new length of %s, failing\n"),
  616.             (const char*)GetPath());
  617.         return FALSE;
  618.         }
  619.     if ((nErr = _dos_close(handle)) != 0)
  620.         {
  621.         TRACE(TEXT("CPathSpec::DoSetLength : Could not close file %s, failing\n"),
  622.             (const char*)GetPath());
  623.         return FALSE;
  624.         }
  625. #endif
  626.     
  627.     return TRUE;
  628.     }
  629.     
  630. BOOL CPathSpec::DoSetAttributes()
  631.     {
  632.     CFileStatus fileStatus;
  633.     
  634.     if (!CFile::GetStatus(GetPath(), fileStatus))
  635.         {
  636.         TRACE(TEXT("CPathSpec::DoSetAttributes : Could not even get the present status, failing\n"));
  637.         return FALSE;
  638.         }
  639.  
  640.     // Set new attributes
  641.     fileStatus.m_attribute = m_eAttributes;;
  642.     
  643.     BOOL bSuccess = TRUE;
  644.     TRY
  645.         {
  646.         CFile::SetStatus(GetPath(), fileStatus);
  647.         }
  648.     CATCH(CFileException, pxFile)
  649.         {
  650.         TRACE(TEXT("CPathSpec::DoSetAttributes : Catching file exception (cause %XH)"),
  651.                 ((CFileException*)pxFile)->m_cause);
  652.         bSuccess = FALSE;
  653.         }
  654.     END_CATCH
  655.     return bSuccess;
  656.     }
  657.  
  658. // To avoid conflict between '#define new DEBUG_NEW' and 'operator new'
  659. #undef new 
  660.  
  661. void* CPathSpec::operator new(size_t nSize)
  662.     {
  663.     return CDirSpec::operator new(nSize);
  664.     }
  665.     
  666. void CPathSpec::operator delete(void* p)
  667.     {
  668.     CDirSpec::operator delete(p);
  669.     }
  670.     
  671. #ifdef _DEBUG
  672. void CPathSpec::Dump(CDumpContext& dc) const
  673.     {
  674.     CDirSpec::Dump(dc);
  675.     CFileSpec::Dump(dc);
  676.     }
  677.  
  678. void CPathSpec::AssertValid() const
  679.     {
  680.     CDirSpec::AssertValid();
  681.     CFileSpec::AssertValid();
  682.     }
  683. #endif
  684.  
  685. CPathSpec::~CPathSpec()
  686.     {
  687.     }
  688.     
  689. // protected:
  690. HMODULE CPathSpec::GetThisModule()
  691.     // --- In  : 
  692.     // --- Out : 
  693.     // --- Returns : The module handle of the running task
  694.     // --- Effect : 
  695.     {
  696.     HMODULE hThisModule = NULL;
  697.  
  698. #ifdef WIN32
  699.     hThisModule = GetModuleHandle(NULL);
  700. #else    
  701.     // WIN16 does not have a direct function which returns the module handle of the running application
  702.     // Therefor TOOLHELP is used to calculate it from the running task
  703.     HTASK hCurrentTask;
  704.     TASKENTRY taskEntry;
  705.     taskEntry.dwSize = sizeof(taskEntry);
  706.     hCurrentTask = GetCurrentTask();
  707.     if (hCurrentTask == NULL)
  708.             return NULL;
  709.     TaskFindHandle(&taskEntry, hCurrentTask);
  710.     hThisModule = taskEntry.hModule;
  711.  
  712.     // An alternative (but undocumented) ways is the following
  713.     // HMODULE hThisModule2 = (HMODULE)*(LPWORD)MAKELP(GetCurrentTask(), 0x1E);
  714. #endif
  715.     
  716.     return hThisModule;
  717.     }
  718.  
  719. BOOL CPathSpec::SearchEnvironment(const char* pszFileName, const char* pszVarName, char* pszPathName)
  720.     // --- In  : pszFileName : The name of the file to search for
  721.     //             pszVarName : The name of the environment variable
  722.     // --- Out : pszPathName : The full path of the file if found, otherwise empty
  723.     // --- Returns : Whether the specified file was found
  724.     // --- Effect : Searches all the directories of the specified environment variable
  725.     //                for the specified file
  726.     //                An environment variable is case-sensitive
  727.     // --- Remark : This function is an implementation of the C-RunTime function _searchenv
  728.     //                 This function also works when called from a DLL, which _searchenv does not
  729.     {
  730.     const int nMaxEntriesLength(300);
  731.     char szEntries[nMaxEntriesLength + 1];
  732.     char* pszToken;
  733.     DWORD dwEntriesLength;
  734.     
  735.     // ... Assume failure, so initialize out-parameter
  736.     ASSERT(pszPathName != NULL);
  737.     ASSERT(AfxIsValidAddress(pszPathName, 1));
  738.     *pszPathName = '\0';    
  739.     
  740.     // ... First get the environment value
  741.     dwEntriesLength = GetEnvironmentVar(pszVarName, szEntries, nMaxEntriesLength);
  742.     if (dwEntriesLength == 0)
  743.         // ... Failure : Environment variable does not exist
  744.         return FALSE;
  745. #ifdef _DEBUG    
  746.     if (nMaxEntriesLength < dwEntriesLength)
  747.         TRACE(TEXT("CPathSpec::SearchEnv : Environment variable value length (%u) exceeds maximum length (%u) and will be truncated\n"),
  748.             dwEntriesLength, nMaxEntriesLength);
  749. #endif    
  750.     
  751.     // Iterate all the directory entries, which are seperated by a semi-colon
  752.     BOOL bFound = FALSE;
  753.     CFileStatus fileStatus;
  754.     char szPath[_MAX_PATH];
  755.     char* pszConcat;
  756.     pszToken = strtok(szEntries, TEXT(";"));
  757.     while (!bFound && (pszToken != NULL))
  758.         {
  759.         strcpy(szPath, pszToken);
  760.         // ... String cannot be empty because (pszToken != '\0')
  761.         ASSERT(1 <= strlen(szPath));
  762.         // ... Examine the last char of the directory spec, 
  763.         //     if it is not back slash and not a colon (relative path), add a back slash
  764.         pszConcat = &szPath[strlen(szPath) - 1];
  765.         if ( (*pszConcat != '\\') && (*pszConcat != ':') )
  766.             *(++pszConcat) = '\\';
  767.         // ... Position after last char of directory spec
  768.         pszConcat++;
  769.         // ... Add file name
  770.         strcpy(pszConcat, pszFileName);
  771.         bFound = CFile::GetStatus(szPath, fileStatus);
  772.         pszToken = strtok(NULL, TEXT(";"));
  773.         }
  774.     if (bFound)
  775.         {
  776.         ASSERT(AfxIsValidAddress(pszPathName, strlen(szPath) + 1));
  777.         strcpy(pszPathName, szPath);
  778.         }
  779.     return bFound;
  780.     }
  781.  
  782. DWORD CPathSpec::GetEnvironmentVar(const char* pszVarName, char* pszValue, DWORD nLength)
  783.     // --- In  : pszVarName : The name of the environment variable 
  784.     //             pszValue : Buffer into which the result will be stored
  785.     //             nLength : The length of the buffer
  786.     // --- Out : pszValue : The result (the environment table entry containing 
  787.     //                 the current string value of pszVarName)
  788.     // --- Returns : The number of characters stored into the buffer pointed to by pszValue, 
  789.     //                  not including the terminating null character. 
  790.     //                 When the variable name was not found the return value is zero. 
  791.     //                 If the buffer pointed to by pszValue is not large enough, 
  792.     //                  the return value is the buffer size, in characters, 
  793.     //                  required to hold the value string and its terminating null character. 
  794.     // --- Effect : Searches the list of environment variables for the specified entry
  795.     //                An environment variable is case-sensitive
  796.     // --- Remark : This function is an implementation of the C-RunTime function getenv
  797.     //                 This function also works when called from a DLL, which in WIN16 getenv does not
  798.     //                See Also MS Developers Network Q78542 : 
  799.     //                 Retreiving MS-DOS Environment Vars from a Windows DLL
  800.     {
  801. #ifdef WIN32
  802.     // Functionality exists in WIN32, so just call Windows API function
  803.     return ::GetEnvironmentVariable(pszVarName, pszValue, nLength);
  804. #else    
  805.     // ... Assume failure, so initialize out-parameter
  806.     ASSERT(pszValue != NULL);
  807.     ASSERT(AfxIsValidAddress(pszValue, (UINT)nLength));
  808.     *pszValue = '\0';    
  809.  
  810.     char* lpEnvSearch;
  811.     const char* lpszVarSearch;
  812.     
  813.     // ... Check for empty var
  814.     if (*pszVarName == '\0')
  815.         {
  816.         TRACE(TEXT("CPathSpec::GetEnvironmentVar : Empty environment variable, returning 0\n"));
  817.         return 0;
  818.         }
  819.         
  820.     //  ... Get a pointer to the MS-DOS environment block
  821.     lpEnvSearch = GetDOSEnvironment();
  822.     // ... Iterat all strings in the environment table
  823.     while (*lpEnvSearch != '\0')
  824.         {
  825.         //  ... Check to see if the variable names match
  826.         lpszVarSearch = pszVarName;
  827.         while ( (*lpEnvSearch != '\0') && (*lpszVarSearch != '\0') &&
  828.                 (*lpEnvSearch == *lpszVarSearch) )
  829.             {
  830.               lpEnvSearch++;
  831.               lpszVarSearch++;
  832.               }
  833.         // ... If the names match, the lpEnvSearch pointer is on the "="
  834.         //     character and lpszVarSearch is on a null terminator.
  835.         //     Increment and return lpszEnvSearch, which will point to the
  836.         //     environment variable's contents.
  837.         if ((*lpEnvSearch == '=') && (*lpszVarSearch == '\0'))
  838.             {
  839.             lpEnvSearch++;
  840.             strncpy(pszValue, lpEnvSearch, (size_t)nLength);
  841.             pszValue[nLength] = '\0';
  842.             return strlen(lpEnvSearch);
  843.             }
  844.         // ... If the names do not match, increment lpEnvSearch until it
  845.         //     reaches the end of the current variable string.
  846.         else
  847.               while (*lpEnvSearch != '\0')
  848.                 lpEnvSearch++;
  849.         // ... At this point the end of the environment variable's string
  850.         //        has been reached. Increment lpEnvSearch to move to the
  851.         //     next variable in the environment block. If it is NULL,
  852.         //     the end of the environment block has been reached.
  853.         lpEnvSearch++;
  854.         }
  855.         
  856.     // If this section of code is reached, the variable was not found.
  857.     TRACE(TEXT("CPathSpec::GetEnvironmentVar : Environment variable (%s) not found, returning NULL\n"), pszVarName);
  858.       return 0; 
  859. #endif // WIN32      
  860.     }
  861.     
  862. BOOL CPathSpec::GetFirstFile(CPathIterator& FIterator) const
  863.     {
  864.     CPathSpec searchPath(*this);
  865.     if (searchPath.GetFileName().IsEmpty())
  866.         VERIFY(searchPath.SetFileName(TEXT("*.*")));
  867.  
  868.     BOOL bGoodFileFound = FALSE;    
  869.     BOOL bJustFileFound = TRUE;    
  870.     FIterator.m_bValid = TRUE;
  871.  
  872. #ifdef WIN32
  873.     FIterator.m_hFindFile = FindFirstFile(searchPath.GetPath(), &FIterator.m_FindFileData);
  874.  
  875.     if (FIterator.m_hFindFile == INVALID_HANDLE_VALUE)
  876.         {
  877.         FindClose(FIterator.m_hFindFile);
  878.         FIterator.m_hFindFile = NULL;
  879.         FIterator.m_bValid = FALSE;
  880.         }
  881.     else
  882.         {
  883.         while (!bGoodFileFound && bJustFileFound)
  884.             {
  885.             if (!IsChildDir(&FIterator.m_FindFileData) &&
  886.                (FIterator.m_FindFileData.cFileName[0] != __TEXT('.')))
  887.                 bGoodFileFound = TRUE;
  888.             
  889.             if (!bGoodFileFound)
  890.                 bJustFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  891.             }
  892.         }
  893. #else
  894.     
  895.     bGoodFileFound = !_dos_findfirst(searchPath.GetPath(), _A_NORMAL | _A_ARCH, &FIterator.m_FileInfo);
  896.         
  897. #endif
  898.  
  899.        FIterator.m_bValid = bGoodFileFound;
  900.     return FIterator.m_bValid;
  901.     }
  902.     
  903. CFileSpec CPathSpec::GetNextFile(CPathIterator& FIterator) const
  904.     {
  905.     ASSERT_VALID(&FIterator);
  906.  
  907.     CFileSpec ActualFile;
  908.  
  909.     BOOL bDirFound(TRUE);
  910. #ifdef WIN32
  911.     BOOL bFileFound;
  912.     ActualFile.SetFileName(FIterator.m_FindFileData.cFileName);
  913.     ActualFile.SetTime(CTime(FIterator.m_FindFileData.ftLastWriteTime));
  914.     ASSERT(FIterator.m_FindFileData.nFileSizeHigh == 0);
  915.     ActualFile.SetLength(FIterator.m_FindFileData.nFileSizeLow);
  916.     ActualFile.SetAttributes((CFile::Attribute)FIterator.m_FindFileData.dwFileAttributes);
  917.  
  918.     bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  919.     while (bFileFound && bDirFound)
  920.         {
  921.         if (!IsChildDir(&FIterator.m_FindFileData) &&
  922.            (FIterator.m_FindFileData.cFileName[0] != __TEXT('.')))
  923.             bDirFound = FALSE;
  924.         
  925.         if (bDirFound)
  926.             bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  927.             }
  928.         
  929.     if (!bFileFound)    
  930.         {
  931.         FindClose(FIterator.m_hFindFile);
  932.         FIterator.m_hFindFile = NULL;
  933.         FIterator.m_bValid = FALSE;
  934.         }
  935.  
  936. #else
  937.     ActualFile.SetFileName(FIterator.m_FileInfo.name);
  938.     ActualFile.SetTime(CTime((WORD)FIterator.m_FileInfo.wr_date, (WORD)FIterator.m_FileInfo.wr_time));
  939.     ActualFile.SetLength(FIterator.m_FileInfo.size);
  940.     ActualFile.SetAttributes((CFile::Attribute)FIterator.m_FileInfo.attrib);
  941.     
  942.     if (_dos_findnext(&FIterator.m_FileInfo) != 0)
  943.         {
  944.            FIterator.m_bValid = FALSE;
  945.         }
  946. #endif                
  947.  
  948.     return ActualFile;
  949.     }
  950.     
  951. BOOL CPathSpec::GetFirstDir(CPathIterator& FIterator) const                 
  952.     {
  953.     CPathSpec searchPath(*this);
  954.     if (searchPath.GetFileName().IsEmpty())
  955.         VERIFY(searchPath.SetFileName(TEXT("*.*")));
  956.  
  957.     FIterator.m_bValid = TRUE;
  958.     BOOL bFileFound(TRUE);    
  959.     BOOL bDirFound(FALSE);    
  960.  
  961. #ifdef WIN32
  962.     FIterator.m_hFindFile = FindFirstFile(searchPath.GetPath(), &FIterator.m_FindFileData);
  963.  
  964.     if (FIterator.m_hFindFile == INVALID_HANDLE_VALUE)
  965.         {
  966.         FindClose(FIterator.m_hFindFile);
  967.         FIterator.m_hFindFile = NULL;
  968.         FIterator.m_bValid = FALSE;
  969.         }
  970.     else
  971.         {
  972.         while (!bDirFound && bFileFound)
  973.             {
  974.             if (IsChildDir(&FIterator.m_FindFileData))
  975.                 bDirFound = TRUE;
  976.             
  977.             if (!bDirFound)
  978.                 bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  979.             }
  980.         }
  981.     
  982. #else
  983.     bFileFound = !_dos_findfirst(searchPath.GetPath(), _A_NORMAL | _A_ARCH | _A_SUBDIR, &FIterator.m_FileInfo);
  984.        while (bFileFound && !bDirFound)
  985.         {
  986.         if ((FIterator.m_FileInfo.attrib & _A_SUBDIR) && (strcmp(FIterator.m_FileInfo.name, TEXT(".")) != 0) &&
  987.             (strcmp(FIterator.m_FileInfo.name, TEXT("..")) != 0))
  988.             bDirFound = TRUE;
  989.         
  990.         if (!bDirFound)    
  991.             bFileFound = (_dos_findnext(&FIterator.m_FileInfo) == 0);
  992.         }        
  993.        
  994. #endif
  995.  
  996.        FIterator.m_bValid = bDirFound;
  997.     return FIterator.m_bValid;    
  998.     }
  999.  
  1000. CDirSpec CPathSpec::GetNextDir(CPathIterator& FIterator) const
  1001.     {
  1002.     ASSERT_VALID(&FIterator);
  1003.      
  1004.     CDirSpec ActualDir;
  1005.  
  1006.     BOOL bFileFound;    
  1007.     BOOL bDirFound(FALSE);    
  1008.  
  1009. #ifdef WIN32
  1010.     ActualDir.SetDrive(m_sDrive);
  1011.     ActualDir.SetSubdirectory(m_sSubdirectory);
  1012.     ActualDir.AppendDirectory(CDirSpec(FIterator.m_FindFileData.cFileName));
  1013.  
  1014.     bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  1015.     while (bFileFound && !bDirFound)
  1016.         {
  1017.         if (IsChildDir(&FIterator.m_FindFileData))
  1018.             bDirFound = TRUE;
  1019.  
  1020.         if (!bDirFound)
  1021.             bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
  1022.         }
  1023.         
  1024.     if (!bFileFound)    
  1025.         {
  1026.         FindClose(FIterator.m_hFindFile);
  1027.         FIterator.m_hFindFile = NULL;
  1028.         FIterator.m_bValid = FALSE;
  1029.         }
  1030.  
  1031. #else
  1032.  
  1033.     ActualDir.SetDrive(m_sDrive);
  1034.     ActualDir.SetSubdirectory(m_sSubdirectory);
  1035.     ActualDir.AppendDirectory(CDirSpec(FIterator.m_FileInfo.name));
  1036.  
  1037.     bFileFound = !_dos_findnext(&FIterator.m_FileInfo);
  1038.        while (bFileFound && !bDirFound)
  1039.         {
  1040.         if ((FIterator.m_FileInfo.attrib & _A_SUBDIR) && (strcmp(FIterator.m_FileInfo.name, TEXT(".")) != 0) &&
  1041.             (strcmp(FIterator.m_FileInfo.name, TEXT("..")) != 0))
  1042.             bDirFound = TRUE;
  1043.         
  1044.         if (!bDirFound)    
  1045.             bFileFound = (_dos_findnext(&FIterator.m_FileInfo) == 0);
  1046.         }        
  1047.  
  1048.        FIterator.m_bValid = bDirFound;
  1049. #endif                
  1050.  
  1051.     return ActualDir;    
  1052.     }
  1053.     
  1054. // private:
  1055.  
  1056. // ==========================================================================
  1057.